//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "clsinfo.h"
#include "marshal.h"
#include "sharecls.h"
#include "linknode.h"
#include "aura.h"

ECode RegsiterLocalClassInfo(
    /* [in]  */ CIClassInfo *pClassInfo)
{
    if (NULL == pClassInfo) {
        return E_INVALID_ARGUMENT;
    }

    return RegisterSharedClassInfo(pClassInfo);
}

ECode UnregisterClassInfo(
    /* [in]  */ CIClassInfo *pClassInfo)
{
    if (NULL == pClassInfo) {
        return E_INVALID_ARGUMENT;
    }
    return UnregisterSharedClassInfo(pClassInfo);
}

ECode GetLocalClassInfo(
    /* [in]  */ REMuid clsId,
    /* [out] */ CIClassInfo **ppClassInfo)
{
    if (NULL == ppClassInfo) {
        return E_INVALID_ARGUMENT;
    }

    return LookupSharedClassInfo(clsId, ppClassInfo);
}

ECode GetLocalClassEntry(
    /* [in]  */ REMuid clsId,
    /* [out] */ CIClassEntry **ppClassEntry)
{
    if (NULL == ppClassEntry) {
        return E_INVALID_ARGUMENT;
    }

    return LookupSharedClassEntry(clsId, ppClassEntry);
}

#if 0
ECode GetRemoteClassEntry(
    /* [in]  */ UInt32 uChannelId,
    /* [in]  */ REMuid clsId,
    /* [out] */ CIClassEntry **ppClassEntry)
{
    PVoid  pBuf    = NULL;
    UInt32 BufSize = MALLOC_SIZE;

    ECode   ec = NOERROR;
    UInt32  replyType;

    pBuf = (UInt32*)Aura_malloc(BufSize);
    if (NULL == pBuf) {
        return E_OUT_OF_MEMORY;
    }

    SET_REQUEST_TYPE(pBuf,Request_MetaData);
    memcpy((PVoid)BY_REFERENCE(pBuf,1),(PVoid)&clsId, sizeof(EMuid));

    ec = AuraIpcChannel_SyncWrite(uChannelId,
                                pBuf,
                                sizeof(EMuid) + sizeof(UInt32),
                                pBuf,
                                (Aura_UInt32)BufSize);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    GET_REPLY_TYPE(pBuf, replyType);
    assert((Reply_MetaData == replyType) \
           || (Reply_ECodeOnly == replyType));

    GET_REPLY_ECODE(pBuf,ec);
    if (FAILED(ec)) {
        ec = E_FAIL;
        goto ErrorExit;
    }
    else {
        ec = RegisterSharedClassInfo((CIClassInfo*)BY_REFERENCE(pBuf,2));
        if (FAILED(ec)) {
            goto ErrorExit;
        }

        ec = GetLocalClassEntry(clsId,ppClassEntry);
    }

ErrorExit:
    Aura_free(pBuf);
    return ec;
}
#endif

typedef struct BufLinkNode : DLinkNode {
    void *buffer;
} BufLinkNode;


ECode GetRemoteClassEntry(
    /* [in] */ UInt32 uChannelId,
    /* [in] */ REMuid clsId,
    /* [out] */ CIClassEntry ** ppClassEntry)
{
    PVoid  pBuf = NULL;
    UInt32 bufSize = MALLOC_SIZE;

    ECode ec = NOERROR;
    UInt32  replyType;

    pBuf = (UInt32 *)Aura_malloc((Aura_Int32)bufSize);
    if (NULL == pBuf) {
        return E_OUT_OF_MEMORY;
    }

    SET_REQUEST_TYPE(pBuf, Request_MetaData);
    memcpy((PVoid)BY_REFERENCE(pBuf,1),(PVoid)&clsId, sizeof(EMuid));

    ec = (ECode)AuraIpcChannel_AsyncWrite(uChannelId,
                                  (Aura_PVoid)pBuf,
                                  sizeof(EMuid) + sizeof(UInt32));
    if (FAILED(ec)){
        Aura_printf(" ###failed to AsyncWrite. (ec = 0x%x).\n",ec);
        goto ErrorExit;
    }

    {
        ec = (ECode)AuraIpcChannel_Read(uChannelId,(PVoid)pBuf, MALLOC_SIZE);
        if (ec == E_BUFFER_TOO_SMALL) {
            //if the buffer size is too small,
            //malloc some another buffer to read the data left in the pipe
            //and put them into a buffer link
            DLinkNode bufList;
            bufList.Initialize();
            BufLinkNode *pbufNode = new BufLinkNode;
            pbufNode->buffer = pBuf;
            bufList.InsertLast(pbufNode);
            pBuf = NULL;

            Int32 nTotalSize = MALLOC_SIZE;
            do {
                PVoid tempBuf = Aura_malloc(MALLOC_SIZE);
                ec = (ECode)AuraIpcChannel_Read(uChannelId, (PVoid)tempBuf, MALLOC_SIZE);

                pbufNode = new BufLinkNode;
                pbufNode->buffer = tempBuf;
                bufList.InsertLast(pbufNode);

                nTotalSize += MALLOC_SIZE;
            } while (ec == E_BUFFER_TOO_SMALL);

            //merge data in the buffer link into a bigger buffer
            if (FAILED(ec)) {
                while(!bufList.IsEmpty()) {
                    BufLinkNode * p = (BufLinkNode *)bufList.Next();
                    p->Detach();
                    Aura_free(p->buffer);
                    delete p;
                }
                goto ErrorExit;
            }
            else {
                PVoid biggerBuf = Aura_malloc((Aura_Int32)nTotalSize);
                char *q = (char *)biggerBuf;
                while(!bufList.IsEmpty()) {
                    BufLinkNode * p = (BufLinkNode *)bufList.Next();
                    p->Detach();
                    Aura_memcpy(q, p->buffer, MALLOC_SIZE);
                    q += MALLOC_SIZE;
                    Aura_free(p->buffer);
                    delete p;
                }
                pBuf = biggerBuf;
            }
        }

        if (FAILED(ec)) {
            goto ErrorExit;
        }
    }

    GET_REPLY_TYPE(pBuf, replyType);
    assert((Reply_MetaData == replyType) \
           || (Reply_ECodeOnly == replyType));

    GET_REPLY_ECODE(pBuf,ec);
    if (FAILED(ec)) {
        ec = E_FAIL;
        goto ErrorExit;
    }
    else {
        ec = RegisterSharedClassInfo((CIClassInfo*)BY_REFERENCE(pBuf,2));
        if (FAILED(ec)) {
            goto ErrorExit;
        }

        ec = GetLocalClassEntry(clsId,ppClassEntry);
    }

ErrorExit:
    if (NULL != pBuf) {
        Aura_free(pBuf);
    }
    return ec;
}

